package ChatSystem;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * A message, either a file or a textual one. It is meant to be par of a User's conversation.
 */
public abstract class ChatMessage {
	private final Date _timestamp;
	private final User _sender;
	private final User _recipient;
	private final static DateFormat _dateFormat = new SimpleDateFormat("HH:mm:ss");

	/**
	 * Initializes that common attributes of a message.
	 * @param timestamp The date the message was sent or received
	 * @param sender The sender of the message
	 * @param recipient The recipient of the message
	 */
	public ChatMessage(Date timestamp, User sender, User recipient) {
		_timestamp = timestamp;
		_sender = sender;
		_recipient = recipient;
	}

	/**
	 * The date the message was sent or received
	 * @return The date the message was sent or received
	 */
	public Date getTimestamp() {
		return _timestamp;
	}

	/**
	 * The sender of the message
	 * @return The sender of the message
	 */
	public User getSender() {
		return _sender;
	}
	
	/**
	 * The recipient of the message
	 * @return The recipient of the message
	 */
	public User getRecipient() {
		return _recipient;
	}
	
	/**
	 * Formats the message to display it in a conversation
	 * @return The formatted message
	 */
	@Override
	public String toString() {
		return _dateFormat.format(_timestamp) + " " + _sender.getNickname();
	}
	
	/**
	 * A textual message meant to be part of a User conversation.
	 */
	public static class ChatTextMessage extends ChatMessage {
		private final String _message;
		private boolean _received;

		/**
		 * Creates the message with a text body.
		 * @param msg The body of the text message
		 * @param timestamp The date the message was sent or received
		 * @param sender The sender of the message
		 * @param recipient The recipient of the message
		 */
		public ChatTextMessage(String msg, Date timestamp, User sender, User recipient) {
			super(timestamp, sender, recipient);
			_message = msg;
			_received = false;
		}

		/**
		 * Provides access to the text body of the message.
		 * @return The text of the message
		 */
		public String getMessage() {
			return _message;
		}
		
		/**
		 * Checks whether an acknowledgement has been received by the sender of the message.
		 * @return A reception acknowledgement.
		 */
		public boolean isReceived() {
			synchronized(this) {
				return _received;
			}
		}
		
		/**
		 * Checks whether an acknowledgement has been received by the sender of the message.
		 */
		public void setReceived() {
			synchronized(this) {
				_received = true;
			}
		}
		
		/**
		 * Formats the message to display it in a conversation
		 * @return The formatted message
		 */
		@Override
		public String toString() {
			String val = super.toString();
			val += " - " + _message;
			if(this.isReceived()) {
				val += " (received)";
			}
			
			return val;
		}
	}
	
	/**
	 * A file message meant to be part of a User conversation.
	 */
	public static class ChatFileMessage extends ChatMessage {
		private final File _savePath;
		private final String _filename;
		private State _state;
		
		/**
		 * The transmission state of the message.
		 */
		public enum State {Pending, Transfer, Completed, Declined, Error};
		
		/**
		 * Creates the message with a text body.
		 * @param filename The file name of the file to be transmitted
		 * @param savePath The path where the file is stored on disk.
		 * @param timestamp The date the message was sent or received
		 * @param sender The sender of the message
		 * @param recipient The recipient of the message
		 */
		public ChatFileMessage(String filename, File savePath, Date timestamp, User sender, User recipient) {
			super(timestamp, sender, recipient);
			_savePath = savePath;
			_filename = filename;
			_state = State.Pending;
		}

		/**
		 * Gets the path where the file is stored on disk. 
		 * @return The path where the file is stored on disk.
		 */
		public String getPath() {
			return _savePath.getAbsolutePath();
		}
		
		/**
		 * Gets the file name of the file to be transmitted
		 * @return The file name of the file to be transmitted
		 */
		public String getFilename() {
			return _filename;
		}
		
		/**
		 * Changes the transfer state of the message and notifies the ChatController of this change.
		 * @param s The new state of the file message
		 */
		public void setState(State s) {
			synchronized(_state) {
				_state = s;
			}
			
			ChatController.getInstance().notifyFileStatusChange(this);
		}
		
		/**
		 * Formats the message to display it in a conversation
		 * @return The formatted message
		 */
		@Override
		public String toString() {
			String val = super.toString();
			val += " - " + _filename;
			
			synchronized(_state) {
				switch(_state) {
				case Pending:
					val += " - (pending…)";
					break;
				case Transfer:
					val += " - (transfering…)";
					break;
				case Completed:
					val += " - (completed)";
					break;
				case Declined:
					val += " - (declined)";
					break;
				case Error:
					val += " - ERROR";
					break;
				}
			}
			
			return val;
		}
	}
}
